#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
线上歌词抓取示例脚本

使用说明：
1. 首先需要安装requests库：pip install requests
2. 运行此脚本：python lyrics_fetcher.py

此示例演示如何从网易云音乐API抓取歌词
"""

import requests
import json
import urllib.parse
import time
import random

class LyricsFetcher:
    """歌词抓取器类，支持从多个API获取歌词"""
    
    def __init__(self):
        # 网易云音乐搜索API
        self.netease_search_api = "https://music.163.com/api/search/get"
        # 网易云音乐歌词API
        self.netease_lyrics_api = "https://music.163.com/api/song/lyric"
        
        # 酷我音乐歌词API
        self.kuwo_search_api = "http://www.kuwo.cn/api/www/search/searchMusicBykeyWord"
        self.kuwo_lyrics_api = "http://m.kuwo.cn/newh5/singles/songinfoandlrc"
        
        # 请求头，模拟浏览器
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Referer": "https://music.163.com"
        }
        
        self.kuwo_headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Referer": "http://www.kuwo.cn",
            "Cookie": "kw_token=test_token"
        }
        
        # 重试参数
        self.max_retries = 3
        self.retry_delay = 2  # 秒
    
    def _request_with_retry(self, url, params=None, headers=None, is_json=True):
        """带重试机制的请求方法"""
        headers = headers or self.headers
        
        for i in range(self.max_retries):
            try:
                # 添加随机延迟避免被封
                time.sleep(random.uniform(0.5, 1.5))
                
                response = requests.get(url, params=params, headers=headers, timeout=10)
                response.raise_for_status()
                
                if is_json:
                    return response.json()
                else:
                    return response.text
            except Exception as e:
                if i == self.max_retries - 1:
                    print(f"请求失败，已重试{self.max_retries}次：{str(e)}")
                    return None
                
                print(f"请求失败，{self.retry_delay}秒后重试（{i+1}/{self.max_retries}）：{str(e)}")
                time.sleep(self.retry_delay)
        
        return None
    
    def search_song(self, song_name, artist_name="", source="netease"):
        """搜索歌曲，获取歌曲ID"""
        try:
            # 构建搜索关键词
            keyword = f"{song_name} {artist_name}".strip()
            
            if source == "netease":
                # 网易云音乐搜索
                params = {
                    "s": keyword,
                    "type": 1,  # 1表示搜索歌曲
                    "offset": 0,
                    "limit": 10
                }
                
                data = self._request_with_retry(self.netease_search_api, params=params)
                
                if data and data.get("code") == 200 and data.get("result", {}).get("songCount", 0) > 0:
                    # 返回搜索到的第一首歌的信息
                    song = data["result"]["songs"][0]
                    return {
                        "song_id": song["id"],
                        "song_name": song["name"],
                        "artist": ", ".join([artist["name"] for artist in song["artists"]]),
                        "album": song["album"]["name"],
                        "source": "netease"
                    }
            elif source == "kuwo":
                # 酷我音乐搜索
                params = {
                    "key": keyword,
                    "pn": 1,
                    "rn": 10
                }
                
                data = self._request_with_retry(self.kuwo_search_api, params=params, headers=self.kuwo_headers)
                
                if data and data.get("code") == 200 and data.get("data", {}).get("list", []):
                    # 返回搜索到的第一首歌的信息
                    song = data["data"]["list"][0]
                    return {
                        "song_id": song["rid"],
                        "song_name": song["name"],
                        "artist": song["artist"],
                        "album": song["album"],
                        "source": "kuwo"
                    }
            
            print(f"未找到歌曲：{keyword}（{source}）")
            return None
        except Exception as e:
            print(f"搜索歌曲时出错：{str(e)}")
            return None
    
    def get_lyrics(self, song_id, source="netease"):
        """根据歌曲ID获取歌词"""
        try:
            lyrics = {}
            
            if source == "netease":
                # 网易云音乐获取歌词
                params = {
                    "id": song_id,
                    "lv": -1,  # -1表示获取所有版本的歌词
                    "kv": -1,
                    "tv": -1
                }
                
                data = self._request_with_retry(self.netease_lyrics_api, params=params)
                
                if data:
                    # 获取普通歌词
                    if "lrc" in data and "lyric" in data["lrc"]:
                        # 统计歌词行数，大于5行才算找到歌词
                        newline_char = '\n'
                        lyric_lines_count = len(data["lrc"]["lyric"].split(newline_char))
                        if lyric_lines_count > 5:
                            lyrics["lrc"] = data["lrc"]["lyric"]
                    
                    # 获取翻译歌词
                    if "tlyric" in data and "lyric" in data["tlyric"]:
                        lyrics["translated"] = data["tlyric"]["lyric"]
            elif source == "kuwo":
                # 酷我音乐获取歌词
                params = {
                    "musicId": song_id
                }
                
                data = self._request_with_retry(self.kuwo_lyrics_api, params=params, headers=self.kuwo_headers)
                
                if data and data.get("code") == 200 and "data" in data:
                    lyric_data = data["data"]
                    
                    # 获取普通歌词
                    if "lrcContent" in lyric_data and lyric_data["lrcContent"]:
                        # 统计歌词行数，大于5行才算找到歌词
                        newline_char = '\n'
                        lyric_lines_count = len(lyric_data["lrcContent"].split(newline_char))
                        if lyric_lines_count > 5:
                            lyrics["lrc"] = lyric_data["lrcContent"]
            
            return lyrics
        except Exception as e:
            print(f"获取歌词时出错：{str(e)}")
            return {}
    
    def fetch_lyrics_by_name(self, song_name, artist_name="", source="netease"):
        """通过歌名和歌手名获取歌词"""
        # 1. 搜索歌曲获取ID
        song_info = self.search_song(song_name, artist_name, source)
        
        if not song_info:
            # 如果指定源没找到，尝试其他源
            if source == "netease":
                print(f"尝试从酷我音乐搜索：{song_name} - {artist_name}")
                song_info = self.search_song(song_name, artist_name, "kuwo")
            else:
                print(f"尝试从网易云音乐搜索：{song_name} - {artist_name}")
                song_info = self.search_song(song_name, artist_name, "netease")
        
        if not song_info:
            return None, None
        
        # 2. 根据歌曲ID和来源获取歌词
        lyrics = self.get_lyrics(song_info["song_id"], song_info["source"])
        
        # 3. 如果没有获取到歌词，尝试另一个源
        if not lyrics.get("lrc"):
            other_source = "kuwo" if song_info["source"] == "netease" else "netease"
            print(f"在{song_info['source']}未找到歌词，尝试从{other_source}获取")
            
            # 重新搜索并获取歌词
            other_song_info = self.search_song(song_name, artist_name, other_source)
            if other_song_info:
                other_lyrics = self.get_lyrics(other_song_info["song_id"], other_source)
                if other_lyrics.get("lrc"):
                    return other_song_info, other_lyrics
        
        return song_info, lyrics
    
    def save_lyrics_to_file(self, song_info, lyrics, folder="."):
        """保存歌词到文件"""
        if not song_info or not lyrics.get("lrc"):
            print("没有可保存的歌词信息")
            return False
        
        try:
            # 生成文件名
            safe_song_name = "".join([c for c in song_info["song_name"] if c not in '\\/:*?"<>|'])
            safe_artist_name = "".join([c for c in song_info["artist"] if c not in '\\/:*?"<>|'])
            file_name = f"{safe_song_name} - {safe_artist_name}.lrc"
            file_path = os.path.join(folder, file_name)
            
            # 保存歌词内容
            with open(file_path, "w", encoding="utf-8") as f:
                if lyrics.get("lrc"):
                    f.write(lyrics["lrc"])
                    
                # 如果有翻译歌词，添加到文件末尾
                if lyrics.get("translated") and lyrics["translated"].strip():
                    f.write("\n\n[翻译歌词]\n")
                    f.write(lyrics["translated"])
            
            print(f"歌词已保存到：{file_path}")
            return True
        except Exception as e:
            print(f"保存歌词到文件时出错：{str(e)}")
            return False
    
    def batch_fetch_lyrics(self, song_list, save_to_file=False, folder="."):
        """批量获取歌词"""
        results = []
        
        for i, (song_name, artist_name) in enumerate(song_list, 1):
            print(f"\n--- 处理歌曲 {i}/{len(song_list)}: {song_name} - {artist_name} ---")
            song_info, lyrics = self.fetch_lyrics_by_name(song_name, artist_name)
            
            if song_info and lyrics:
                results.append((song_info, lyrics))
                
                if save_to_file:
                    self.save_lyrics_to_file(song_info, lyrics, folder)
            else:
                print(f"无法获取歌词：{song_name} - {artist_name}")
                results.append((None, None))
        
        return results


# # 示例用法
# if __name__ == "__main__":
#     import os
    
#     # 创建歌词抓取器实例
#     fetcher = LyricsFetcher()
    
#     print("====== 歌词抓取工具演示 ======")
#     print("1. 单首歌曲歌词抓取")
#     print("2. 批量歌曲歌词抓取")
#     print("3. 测试不同歌词源")
    
#     # 创建歌词保存目录
#     lyrics_folder = "lyrics"
#     if not os.path.exists(lyrics_folder):
#         os.makedirs(lyrics_folder)
    
#     # 测试1: 单首歌曲歌词抓取（选择有完整歌词的流行歌曲）
#     print("\n\n====== 测试1: 单首歌曲歌词抓取 ======")
#     song_name = "起风了"
#     artist_name = "买辣椒也用券"
#     print(f"\n--- 搜索歌曲：{song_name} - {artist_name} ---")
#     song_info, lyrics = fetcher.fetch_lyrics_by_name(song_name, artist_name)
    
#     if song_info:
#         print(f"找到歌曲：{song_info['song_name']} - {song_info['artist']}（专辑：{song_info['album']}，来源：{song_info['source']}）")
#         if lyrics.get("lrc"):
#             print("\n歌词：")
#             # 显示整首歌词
#             lrc_lines = lyrics["lrc"].split("\n")
#             print("\n".join(lrc_lines))
        
#         if lyrics.get("translated"):
#             print("\n翻译歌词：")
#             trans_lines = lyrics["translated"].split("\n")
#             print("\n".join(trans_lines))
        
#         # 保存歌词到文件
#         fetcher.save_lyrics_to_file(song_info, lyrics, lyrics_folder)
#     else:
#         print(f"未找到歌曲：{song_name} - {artist_name}")
    
#     # 测试2: 批量歌曲歌词抓取
#     print("\n\n====== 测试2: 批量歌曲歌词抓取 ======")
#     song_list = [
#         ("Beyond", "海阔天空"),
#         ("夜曲", "周杰伦"),
#         ("演员", "薛之谦"),
#         ("光年之外", "邓紫棋")
#     ]
    
#     print(f"开始批量处理 {len(song_list)} 首歌曲...")
#     results = fetcher.batch_fetch_lyrics(song_list, save_to_file=True, folder=lyrics_folder)
    
#     # 统计成功数量
#     success_count = sum(1 for song_info, _ in results if song_info)
#     print(f"\n批量处理完成，成功获取 {success_count}/{len(song_list)} 首歌曲的歌词")
#     print(f"歌词文件已保存到：{os.path.abspath(lyrics_folder)}")
    
#     # 测试3: 测试不同歌词源
#     print("\n\n====== 测试3: 测试不同歌词源 ======")
#     test_song = "可惜没如果"
#     test_artist = "林俊杰"
    
#     print(f"\n--- 从网易云音乐获取：{test_song} - {test_artist} ---")
#     song_info1, lyrics1 = fetcher.fetch_lyrics_by_name(test_song, test_artist, source="netease")
    
#     print(f"\n--- 从酷我音乐获取：{test_song} - {test_artist} ---")
#     song_info2, lyrics2 = fetcher.fetch_lyrics_by_name(test_song, test_artist, source="kuwo")
    
#     # 对比两个来源的结果
#     if song_info1 and lyrics1.get("lrc"):
#         # 修复f-string中的反斜杠问题
#         newline_char = '\n'
#         lyric_lines_count = len(lyrics1['lrc'].split(newline_char))
#         print(f"\n网易云音乐结果：成功获取歌词，歌词行数: {lyric_lines_count}")
    
#     if song_info2 and lyrics2.get("lrc"):
#         # 修复f-string中的反斜杠问题
#         newline_char = '\n'
#         lyric_lines_count = len(lyrics2['lrc'].split(newline_char))
#         print(f"酷我音乐结果：成功获取歌词，歌词行数: {lyric_lines_count}")
    
#     print("\n\n====== 歌词抓取工具演示完成 ======")
#     print("\n使用说明：")
#     print("1. 您可以修改代码中的歌曲列表来抓取其他歌曲的歌词")
#     print("2. 所有抓取的歌词已保存到 lyrics 文件夹中")
#     print("3. 工具支持自动切换不同的歌词源以提高成功率")